# 基于Deepseek API实现文本对话，能够通过输入问题来回答我
# API秘钥是sk-bab1e4f901344202b2f514efe1200128
# 要求：能够实现多轮循环对话，模型能够流式输出，使用edge_tts实现文本转语音，支持多种音色选择，可选择是否开启语音播放，实现流式播放语音
#

from openai import OpenAI
import sys
import asyncio
import edge_tts
import os
import tempfile
import time
from concurrent.futures import ThreadPoolExecutor

# 创建临时目录用于存储语音文件
TEMP_DIR = tempfile.gettempdir()

# 定义常用的中文音色
CHINESE_VOICES = {
    "1": "zh-CN-XiaoxiaoNeural",   # 女声（默认）
    "2": "zh-CN-YunxiNeural",      # 男声
    "3": "zh-CN-XiaoyiNeural",     # 女声（温柔）
    "4": "zh-CN-YunjianNeural",    # 男声（稳重）
    "5": "zh-CN-XiaohanNeural",    # 女声（活泼）
    "6": "zh-CN-XiaomoNeural",     # 女声（成熟）
    "7": "zh-CN-XiaoxuanNeural",   # 女声（温暖）
    "8": "zh-CN-YunyangNeural"     # 男声（成熟）
}

# 默认使用的语音
DEFAULT_VOICE = CHINESE_VOICES["1"]

async def list_voices():
    """获取所有可用的语音列表"""
    voices = await edge_tts.list_voices()
    return voices

async def text_to_speech(text, output_file, voice=DEFAULT_VOICE):
    """将文本转换为语音并保存到文件"""
    communicate = edge_tts.Communicate(text, voice)
    await communicate.save(output_file)

def play_audio(file_path):
    """使用系统默认播放器播放音频文件"""
    if sys.platform == "win32":
        os.system(f'start /min "" "{file_path}"')
    elif sys.platform == "darwin":
        os.system(f"afplay '{file_path}'")
    else:
        os.system(f"xdg-open '{file_path}'")

async def process_tts(text, voice):
    """处理文本到语音的转换并播放"""
    # 创建临时文件
    timestamp = int(time.time())
    audio_file = os.path.join(TEMP_DIR, f"ai_response_{timestamp}.mp3")
    
    # 转换文本到语音
    await text_to_speech(text, audio_file, voice)
    
    # 播放音频
    play_audio(audio_file)
    
    return audio_file

def run_async(coro):
    """运行异步函数"""
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    return loop.run_until_complete(coro)

def show_voice_options():
    """显示可用的语音选项"""
    print("\n可用的语音选项：")
    for key, voice in CHINESE_VOICES.items():
        # 提取语音名称中的性别信息
        gender_info = "女声" if "Xiao" in voice else "男声"
        print(f"  {key}. {voice} ({gender_info})")
    print("\n要切换语音，请输入：/voice <编号> (例如：/voice 2)")

def main():
    # 初始化OpenAI客户端，连接到Deepseek API
    client = OpenAI(
        api_key="sk-bab1e4f901344202b2f514efe1200128",
        base_url="https://api.deepseek.com"
    )
    
    # 初始化对话历史
    messages = [
        {"role": "system", "content": "You are a helpful assistant that provides accurate and informative responses."}
    ]
    
    # 当前使用的语音
    current_voice = DEFAULT_VOICE
    
    # 语音播放状态（默认开启）
    tts_enabled = True
    
    print("欢迎使用Deepseek AI对话助手！输入'退出'或'exit'结束对话。")
    print("已启用语音功能，AI回复将以语音形式播放")
    print("支持多种语音音色，输入'/help'查看可用命令")
    print("-" * 50)
    
    # 创建线程池用于异步处理TTS
    executor = ThreadPoolExecutor(max_workers=1)
    
    while True:
        # 获取用户输入
        user_input = input("\n您: ")
        
        # 检查退出条件
        if user_input.lower() in ['退出', 'exit', 'quit', 'q']:
            print("\n感谢使用，再见！")
            break
        
        # 处理帮助命令
        elif user_input.lower() == '/help':
            print("\n可用命令：")
            print("  /help            - 显示此帮助信息")
            print("  /voice <编号>    - 切换语音音色")
            print("  /voices          - 显示所有可用的语音音色")
            print("  /tts on          - 开启语音播放")
            print("  /tts off         - 关闭语音播放")
            print("  /tts status      - 查看语音播放状态")
            print("  exit 或 退出     - 结束对话")
            continue
        
        # 显示所有可用的语音
        elif user_input.lower() == '/voices':
            show_voice_options()
            continue
        
        # 处理语音播放开关命令
        elif user_input.lower().startswith('/tts '):
            try:
                tts_option = user_input.split(' ')[1].lower()
                if tts_option == 'on':
                    tts_enabled = True
                    print("\n语音播放已开启")
                    
                    # 播放示例以测试
                    test_text = "语音播放已开启。"
                    print(f"播放测试语音: '{test_text}'")
                    executor.submit(run_async, process_tts(test_text, current_voice))
                elif tts_option == 'off':
                    tts_enabled = False
                    print("\n语音播放已关闭")
                elif tts_option == 'status':
                    status = "已开启" if tts_enabled else "已关闭"
                    print(f"\n语音播放状态: {status}")
                else:
                    print(f"\n无效的 TTS 选项: {tts_option}")
                    print("可用选项: on, off, status")
            except (IndexError, ValueError):
                print("\nTTS命令格式错误，请使用 /tts on 或 /tts off")
            continue
        
        # 处理切换语音命令
        elif user_input.lower().startswith('/voice '):
            try:
                voice_option = user_input.split(' ')[1]
                if voice_option in CHINESE_VOICES:
                    current_voice = CHINESE_VOICES[voice_option]
                    voice_type = "女声" if "Xiao" in current_voice else "男声"
                    print(f"\n已切换到语音: {current_voice} ({voice_type})")
                    
                    # 播放示例以测试新语音
                    if tts_enabled:
                        test_text = "您好，这是新选择的语音。"
                        print(f"播放测试语音: '{test_text}'")
                        executor.submit(run_async, process_tts(test_text, current_voice))
                else:
                    print(f"\n无效的语音选项: {voice_option}")
                    show_voice_options()
            except (IndexError, ValueError):
                print("\n语音切换命令格式错误，请使用 /voice <编号>")
                show_voice_options()
            continue
        
        # 将用户消息添加到对话历史
        messages.append({"role": "user", "content": user_input})
        
        print("\nAI: ", end="")
        sys.stdout.flush()  # 确保立即显示
        
        # 流式请求
        try:
            response = client.chat.completions.create(
                model="deepseek-chat",
                messages=messages,
                stream=True  # 启用流式输出
            )
            
            assistant_response = ""
            
            # 处理流式输出
            for chunk in response:
                if chunk.choices[0].delta.content:
                    content = chunk.choices[0].delta.content
                    print(content, end="")
                    sys.stdout.flush()  # 确保内容实时显示
                    assistant_response += content
            
            # 将AI响应添加到对话历史
            messages.append({"role": "assistant", "content": assistant_response})
            print()  # 添加一个换行
            
            # 转换文本为语音并播放（在单独线程中运行异步操作）
            if assistant_response.strip() and tts_enabled:
                print("\n正在生成语音...", end="")
                sys.stdout.flush()
                executor.submit(run_async, process_tts(assistant_response, current_voice))
                print(" 完成")
            
        except Exception as e:
            print(f"\n发生错误: {e}")
    
    # 关闭线程池
    executor.shutdown()

if __name__ == "__main__":
    main()